/* -*-c++-*- */
/* osgGIS - GIS Library for OpenSceneGraph
 * Copyright 2007-2008 Glenn Waldron and Pelican Ventures, Inc.
 * http://osggis.org
 *
 * osgGIS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

#ifndef _OSGGIS_REPORT_H_
#define _OSGGIS_REPORT_H_

#include <osgGIS/Common>
#include <osgGIS/Property>
#include <osg/Timer>
#include <list>

namespace osgGIS
{
    class OSGGIS_EXPORT Report;

    typedef std::vector< osg::ref_ptr<Report> > ReportList;

    /**
     * A summary of information created by some functional process.
     *
     * The reporting mechanism lets any subsystem generate information about
     * the status of its processing responsibilities by generating a Report.
     *
     * Reports can be hierarchical, each Report deliniating summary information
     * about its child reports.
     */
    class OSGGIS_EXPORT Report : public osg::Referenced
    {
    public:
        enum State {
            STATE_OK        =0,
            STATE_WARNING   =10,
            STATE_ERROR     =20
        };

    public:
        /**
         * Constructs a new, empty report
         */
        Report();

        /**
         * Copy constructor
         */
        Report( const Report& rhs );

        /**
         * Sets the name of this report.
         *
         * @param name
         *      A human-readable string
         */
        void setName( const std::string& name );

        /**
         * Gets the name of this report.
         *
         * @return A human-readable string
         */
        const std::string& getName() const;

        /**
         * Updates the overall state of this report. This method will only
         * set the new state if it is "worse" than the previous state (unless
         * you force a state upgrade).
         *
         * @param state
         *      New state to set
         * @param force_downgrade
         *      If true, you can override the current state with a "better"
         *      status (e.g. go from WARNING back to OK). If false (the default),
         *      attempts to upgrade the state are ignored. 
         */
        void setState( State state, bool force_ugprade=false );

        /**
         * Gets the overall status code of the report.
         *
         * @return A status code
         */
        State getState() const;

    public: // statistics

        /**
         * Sets the timing mode so that all the duration measurement functions
         * return information based on aggregating sub-report data instead of
         * local data.
         */
        //TODO

        /**
         * Stores the current time as the start time for duration measurement.
         */
        void markStartTime();

        /**
         * Stores the current time as the end time for duration measurement.
         */
        void markEndTime();

        /** 
         * Gets the total duration based on the first marked start time and the last 
         * marked end time.
         */
        double getDuration() const;
        
        /**
         * Gets the average duration. Each time you call markEndTime()
         * a duration is stored (time from markStartTime() to markEndTime().
         * This method returns the average of all stored durations.
         *
         * @return Average duration, in seconds
         */
        double getAverageDuration() const;

        /**
         * Gets the maximum stored duration. Each time you call markEndTime()
         * a duration is stored (time from markStartTime() to markEndTime().
         * This method returns the maximum of all stored durations.
         *
         * @return Maximum duration, in seconds
         */
        double getMaxDuration() const;

        /**
         * Gets the minimum stored duration. Each time you call markEndTime()
         * a duration is stored (time from markStartTime() to markEndTime().
         * This method returns the minimum of all stored durations.
         *
         * @return Minimum duration, in seconds
         */
        double getMinDuration() const;

    public: // messages

        void notice( const std::string& msg );

        void warning( const std::string& msg );

        void error( const std::string& msg );

        const std::list<std::string>& getMessages() const;

    public: // report nesting

        /**
         * Gets a read-only list of and sub-reports belonging to this report.
         *
         * @return Read-only list of sub-reports
         */
        const ReportList& getSubReports() const;

        /** 
         * Adds a sub-report under this report
         *
         * @param sub_report
         *      Report to add as a sub-report to this report
         */
        void addSubReport( Report* sub_report );

    public: // user-defined properties

        /**
         * Sets one of the report's properties by name.
         */
        void setProperty( const Property& prop );

        /**
         * Gets a collection of all this report's properties.
         */
        const Properties& getProperties() const;

    protected:

        virtual ~Report();
        
    private:
        std::string name;
        State state;
        osg::Timer_t first_start_time, start_time, end_time;
        std::list<double> durations;
        std::list<std::string> messages;
        ReportList sub_reports;
        Properties properties;
    };
}

#endif // _OSGGIS_REPORT_H_
